package com.ts.animal.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.ts.animal.constant.AnimalConstant;
import com.ts.animal.dao.*;
import com.ts.animal.domain.*;
import com.ts.animal.service.BaseStationService;
import com.ts.common.redis.RedisUtil;
import com.ts.common.utils.*;
import com.ts.system.util.SystemUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;


@Service
public class BaseStationServiceImpl implements BaseStationService {

    private static Logger log = LoggerFactory.getLogger(BaseStationServiceImpl.class);

    @Autowired
    private BaseStationDao baseStationDao;
    @Autowired
    private ExInputsDao exInputsDao;
    @Autowired
    private ExBaseStationDao exBaseStationDao;
    @Autowired
    private RfidLabelDao rfidLabelDao;
    @Autowired
    private RfidLabelImportDao rfidLabelImportDao;


    @Override
    public BaseStationDO get(String baseStationNum) {
        return baseStationDao.get(baseStationNum);
    }

    @Override
    public List<Map<String, Object>> list(Map<String, Object> map) {
        String testUserNames[] = SystemUtil.getSystemParams().get(AnimalConstant.key_name_test_user_name).getParamValue().split(",");
        if (Lists.newArrayList(testUserNames).contains(ShiroUtils.getUser().getUsername())) {
            map.put(AnimalConstant.test_user_name, AnimalConstant.test_user_name);
            map.put(AnimalConstant.test_user_deptId, ShiroUtils.getUser().getDeptId());
        } else {
            map.putAll(DataPerUitl.deptPer("bbs.dept_id"));
        }
        boolean checkLabelSwitch = AnimalConstant.open.equals(SystemUtil.getSystemParams().get(AnimalConstant.key_name_check_label_switch).getParamValue());
        if (checkLabelSwitch) {
            map.put(AnimalConstant.open_label_switch, AnimalConstant.open);
        }
        return exBaseStationDao.list(map);
    }

    @Override
    public void baseStationToCache(BaseStationDO... baseStationDOs) {
        if (baseStationDOs == null || baseStationDOs.length == 0) {
            RedisUtil.del(AnimalConstant.REDIS_BASE_STATION_KEY);
            List<BaseStationDO> list = baseStationDao.list(new HashMap<>());
            for (BaseStationDO bsd : list) {
                RedisUtil.hset(AnimalConstant.REDIS_BASE_STATION_KEY, bsd.getBaseStationNum(), bsd);
            }
        } else {
            for (BaseStationDO bsd : baseStationDOs) {
                RedisUtil.hset(AnimalConstant.REDIS_BASE_STATION_KEY, bsd.getBaseStationNum(), bsd);
            }
        }

    }

    @Override
    public List<BaseStationDO> deptSelectBaseStationList(Map<String, Object> map) {
        return exBaseStationDao.deptSelectBaseStationList(map);
    }

    @Override
    public int count(Map<String, Object> map) {
        return baseStationDao.count(map);
    }

    @Override
    public int save(Result result, BaseStationDO baseStation) {
        int ret = baseStationDao.save(baseStation);
        if (ret == 0) {
            result.set(Result.FAIL, "保存失败", null);
        }
        return ret;
    }

    @Override
    public int relateStation(Result result, long deptId, String[] baseStationNumList) {
        int ret = exBaseStationDao.clearRelation(deptId);
        int ret1 = 0;
        if (baseStationNumList.length > 0) {
            ret1 = exBaseStationDao.relateDept(deptId, baseStationNumList);
        }
        int ret2 = exInputsDao.changeInputsDept(deptId);

        boolean checkLabelSwitch = AnimalConstant.open.equals(SystemUtil.getSystemParams().get(AnimalConstant.key_name_check_label_switch).getParamValue());
        String openLabelSwitch = null;
        if (checkLabelSwitch) {
            openLabelSwitch = AnimalConstant.open;
        }
        int ret3 = exInputsDao.insertInputsByDept(deptId, openLabelSwitch);
        return ret + ret1 + ret2 + ret3;
    }

    @Override
    public int update(Result result, BaseStationDO baseStation) {
        int ret = baseStationDao.update(baseStation);
        if (ret == 0) {
            result.set(Result.FAIL, "更新失败", null);
        }
        return ret;
    }

    @Override
    public int remove(Result result, String baseStationNum) {
        int ret = baseStationDao.remove(baseStationNum);
        if (ret == 0) {
            result.set(Result.FAIL, "删除失败", null);
        }
        return ret;
    }

    @Override
    public int batchRemove(Result result, String[] baseStationNums) {
        int ret = baseStationDao.batchRemove(baseStationNums);
        if (ret != baseStationNums.length) {
            result.set(Result.FAIL, "部分删除失败", null);
        }
        return ret;
    }

    @Override
    public void resolveData(String dataString) {
        try {
            if (StringUtils.isEmpty(dataString)) {
                return;
            }

            //检查有效性检查开关 open close
            boolean syncDataValidityCheckSwitch = SystemUtil.getSystemParams().get(AnimalConstant.key_name_sync_data_validity_check_switch).getParamValue().equals(AnimalConstant.open);
            //检查基站名称前缀  有效性检查
            String baseStationNumPrefixArr[] = SystemUtil.getSystemParams().get(AnimalConstant.key_name_base_station_name_prefix).getParamValue().split(",");
            //检查标签号前缀  有效性检查
            String numPrefixArr[] = SystemUtil.getSystemParams().get(AnimalConstant.key_name_num_exclude_prefix).getParamValue().split(",");
            //检查标签号后缀  有效性检查
            String numEndfixArr[] = SystemUtil.getSystemParams().get(AnimalConstant.key_name_num_exclude_endfix).getParamValue().split(",");

            //转换数据
            BaseStationRevOriginalDataDO baseStationRevOriginalDataDO = JSON.parseObject(dataString, BaseStationRevOriginalDataDO.class);
            Date now = new Date();
            //原始数据
            RfidSyncOriginalDataDO rfidSyncOriginalDataDO = new RfidSyncOriginalDataDO();
            rfidSyncOriginalDataDO.setOriginalJsonData(dataString);
            rfidSyncOriginalDataDO.setCreateTime(now);
            //rfidSyncOriginalDataDao.save(rfidSyncOriginalDataDO);
            rfidSyncOriginalDataDOQueue.add(rfidSyncOriginalDataDO);

            if (syncDataValidityCheckSwitch && !StringUtils.startsWithAny(baseStationRevOriginalDataDO.getNo(), baseStationNumPrefixArr)) {
                log.error("传入基站数据异常，基站编号乱码(基站编号为：{})，不予入库。要求基站编号前缀为：{}", baseStationRevOriginalDataDO.getNo(), JSON.toJSONString(baseStationNumPrefixArr));
                return;
            }
            //设置基站离线时间
            long timeout = Long.valueOf(SystemUtil.getSystemParams().get(AnimalConstant.key_name_base_station_status_online_timeout).getParamValue());
            RedisUtil.set(AnimalConstant.REDIS_BASE_STATION_STATUS_KEY + baseStationRevOriginalDataDO.getNo(), AnimalConstant.base_station_status_online, timeout, TimeUnit.MINUTES);

            //基站信息
            BaseStationDO baseStationDO = new BaseStationDO();
            baseStationDO.setBaseStationNum(baseStationRevOriginalDataDO.getNo());
            baseStationDO.setBaseStationModel(baseStationRevOriginalDataDO.getMod());
            baseStationDO.setCreateTime(now);
            baseStationDO.setStatus(AnimalConstant.base_station_status_offline);

            //如果经纬度为空则获取历史数据
            if (baseStationRevOriginalDataDO.getGps().getW() == null || baseStationRevOriginalDataDO.getGps().getS() == null) {
                //判断开关是否开启
                if (AnimalConstant.open.equals(SystemUtil.getSystemParams().get(AnimalConstant.key_name_auto_fill_sw_switch).getParamValue())) {
                    BaseStationDO oldBaseStationDO = RedisUtil.hget(AnimalConstant.REDIS_BASE_STATION_KEY, baseStationRevOriginalDataDO.getNo(), BaseStationDO.class);
                    if (oldBaseStationDO != null) {
                        baseStationRevOriginalDataDO.getGps().setW(oldBaseStationDO.getLongitude());
                        baseStationRevOriginalDataDO.getGps().setS(oldBaseStationDO.getDimension());
                    }
                }
            }
            baseStationDO.setLongitude(baseStationRevOriginalDataDO.getGps().getW());
            baseStationDO.setDimension(baseStationRevOriginalDataDO.getGps().getS());
            baseStationDO.setEastWestLongitude(baseStationRevOriginalDataDO.getGps().getEw());
            baseStationDO.setNorthSouthDimension(baseStationRevOriginalDataDO.getGps().getNs());
            baseStationToCache(baseStationDO);
            baseStationDOQueue.add(baseStationDO);
            //基站数据
            List<RfidSyncDataDO> rfidSyncDataDOList = new ArrayList<RfidSyncDataDO>();
            for (BaseStationRevOriginalDataDO.DaArr data : baseStationRevOriginalDataDO.getDaArr()) {
                if (syncDataValidityCheckSwitch && StringUtils.startsWithAny(data.getEno(), numPrefixArr)) {
                    log.error("传入标签数据异常(标签编号为：{})，不予入库。要求标签编号前缀不为：{}", data.getEno(), JSON.toJSONString(numPrefixArr));
                    continue;
                }
                if (syncDataValidityCheckSwitch && StringUtils.endsWithAny(data.getEno(), numEndfixArr)) {
                    log.error("传入标签数据异常(标签编号为：{})，不予入库。要求标签编号后缀不为：{}", data.getEno(), JSON.toJSONString(numEndfixArr));
                    continue;
                }
                //同步数据
                RfidSyncDataDO rfidSyncDataDO = new RfidSyncDataDO();
                //标签数据
                RfidLabelDO rfidLabelDO = new RfidLabelDO();
                //如果经纬度为空则获取历史数据
//                if (baseStationRevOriginalDataDO.getGps().getW() == null || baseStationRevOriginalDataDO.getGps().getS() == null) {
//                    //判断开关是否开启
//                    if (AnimalConstant.open.equals(SystemUtil.getSystemParams().get(AnimalConstant.key_name_auto_fill_sw_switch).getParamValue())) {
//                        RfidLabelDO oldRfidLabelDO = rfidLabelDao.get(data.getEno());
//                        if (oldRfidLabelDO != null) {
//                            rfidLabelDO.setLongitude(oldRfidLabelDO.getLongitude());//经度
//                            rfidLabelDO.setDimension(oldRfidLabelDO.getDimension());//纬度
//                            rfidSyncDataDO.setLongitude(oldRfidLabelDO.getLongitude());//经度
//                            rfidSyncDataDO.setDimension(oldRfidLabelDO.getDimension());//纬度
//                        }
//                    }
//                } else {
//                    rfidLabelDO.setLongitude(baseStationRevOriginalDataDO.getGps().getW());//经度
//                    rfidLabelDO.setDimension(baseStationRevOriginalDataDO.getGps().getS());//纬度
//                    rfidSyncDataDO.setLongitude(baseStationRevOriginalDataDO.getGps().getW());//经度
//                    rfidSyncDataDO.setDimension(baseStationRevOriginalDataDO.getGps().getS());//纬度
//                }

                rfidSyncDataDO.setLongitude(baseStationRevOriginalDataDO.getGps().getW());//经度
                rfidSyncDataDO.setDimension(baseStationRevOriginalDataDO.getGps().getS());//纬度
                //同步数据
                rfidSyncDataDO.setBaseStationNum(baseStationRevOriginalDataDO.getNo());//基站号
                rfidSyncDataDO.setBaseStationModel(baseStationRevOriginalDataDO.getMod());//基站型号
                rfidSyncDataDO.setEnvironmentTemperature(baseStationRevOriginalDataDO.getRtp());//环境温度
                rfidSyncDataDO.setHumidity(baseStationRevOriginalDataDO.getRh());//湿度
                rfidSyncDataDO.setBodyTemperature(data.getTp());//体温温度
                rfidSyncDataDO.setNum(data.getEno());//芯片号
                rfidSyncDataDO.setSoc(data.getElec());//电量
                rfidSyncDataDO.setCollectionTime(data.getCt());//采集时间
                rfidSyncDataDO.setMovement(data.getSp());//运动量
                rfidSyncDataDO.setEastWestLongitude(baseStationRevOriginalDataDO.getGps().getEw());//东西经
                rfidSyncDataDO.setNorthSouthDimension(baseStationRevOriginalDataDO.getGps().getNs());//南北纬
                rfidSyncDataDO.setCreateTime(now);
                // rfidSyncDataDOList.add(rfidSyncDataDO);
                rfidSyncDataDOQueue.add(rfidSyncDataDO);


                //标签数据
                rfidLabelDO.setLongitude(baseStationRevOriginalDataDO.getGps().getW());//经度
                rfidLabelDO.setDimension(baseStationRevOriginalDataDO.getGps().getS());//纬度
                rfidLabelDO.setBaseStationNum(baseStationRevOriginalDataDO.getNo());//基站号
                rfidLabelDO.setBaseStationModel(baseStationRevOriginalDataDO.getMod());//基站型号
                rfidLabelDO.setEnvironmentTemperature(baseStationRevOriginalDataDO.getRtp());//环境温度
                rfidLabelDO.setHumidity(baseStationRevOriginalDataDO.getRh());//湿度
                rfidLabelDO.setBodyTemperature(data.getTp());//体温温度
                rfidLabelDO.setNum(data.getEno());//芯片号
                rfidLabelDO.setSoc(data.getElec());//电量
                rfidLabelDO.setCollectionTime(data.getCt());//采集时间
                rfidLabelDO.setMovement(data.getSp());//运动量
                rfidLabelDO.setEastWestLongitude(baseStationRevOriginalDataDO.getGps().getEw());//东西经
                rfidLabelDO.setNorthSouthDimension(baseStationRevOriginalDataDO.getGps().getNs());//南北纬
                rfidLabelDO.setCreateTime(now);
                rfidLabelDOQueue.add(rfidLabelDO);
            }

        } catch (Exception e) {
            log.error("解析基站异常，基站数据：{}", dataString);
            e.printStackTrace();
        }
    }

    //原始数据队列
    static ConcurrentLinkedQueue<RfidSyncOriginalDataDO> rfidSyncOriginalDataDOQueue = new ConcurrentLinkedQueue<RfidSyncOriginalDataDO>();
    //基站数据队列
    static ConcurrentLinkedQueue<BaseStationDO> baseStationDOQueue = new ConcurrentLinkedQueue<BaseStationDO>();
    //基站同步数据队列
    static ConcurrentLinkedQueue<RfidSyncDataDO> rfidSyncDataDOQueue = new ConcurrentLinkedQueue<RfidSyncDataDO>();
    //基站同步数据队列
    static ConcurrentLinkedQueue<RfidLabelDO> rfidLabelDOQueue = new ConcurrentLinkedQueue<RfidLabelDO>();

    @Override
    public void batchSaveData() {
        long logSer = System.currentTimeMillis();
        //原始数据批量入库
        try {
            List<RfidSyncOriginalDataDO> rfidSyncOriginalDataDOArray = new ArrayList<RfidSyncOriginalDataDO>();
            while (true) {
                RfidSyncOriginalDataDO rfidSyncOriginalDataDO = rfidSyncOriginalDataDOQueue.poll();
                if (rfidSyncOriginalDataDO != null) {
                    rfidSyncOriginalDataDOArray.add(rfidSyncOriginalDataDO);
                } else {
                    //TODO 入库
                    if (rfidSyncOriginalDataDOArray.size() > 0) {
                        exBaseStationDao.batchSaveRfidSyncOriginalData(rfidSyncOriginalDataDOArray);
                        log.info("{}  原始数据批量入库，队列数据已取完,当前数据长度size：{}", logSer, rfidSyncOriginalDataDOArray.size());
                        //入库之后 清空
                        rfidSyncOriginalDataDOArray.clear();
                    }
                    break;
                }

                if (rfidSyncOriginalDataDOArray.size() >= 1000) {
                    //TODO 入库
                    exBaseStationDao.batchSaveRfidSyncOriginalData(rfidSyncOriginalDataDOArray);
                    log.info("{}  原始数据批量入库，标签数据长度大于1000先入库,当前数据长度size：{}", logSer, rfidSyncOriginalDataDOArray.size());
                    //入库之后 清空
                    rfidSyncOriginalDataDOArray.clear();
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //基站数据批量入库
        try {
            List<BaseStationDO> baseStationDOArray = new ArrayList<BaseStationDO>();
            while (true) {
                BaseStationDO baseStationDO = baseStationDOQueue.poll();
                if (baseStationDO != null) {
                    baseStationDOArray.add(baseStationDO);
                } else {
                    //TODO 入库
                    if (baseStationDOArray.size() > 0) {
                        exBaseStationDao.batchSaveBaseStation(baseStationDOArray);
                        log.info("{}  基站数据批量入库，队列数据已取完,当前数据长度size：{}", logSer, baseStationDOArray.size());
                        //入库之后 清空
                        baseStationDOArray.clear();
                    }
                    break;
                }

                if (baseStationDOArray.size() >= 1000) {
                    //TODO 入库
                    exBaseStationDao.batchSaveBaseStation(baseStationDOArray);
                    log.info("{}  基站数据批量入库，标签数据长度大于1000先入库,当前数据长度size：{}", logSer, baseStationDOArray.size());
                    //入库之后 清空
                    baseStationDOArray.clear();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //基站同步数据批量入库
        try {
            List<RfidSyncDataDO> rfidSyncDataDOQueueArray = new ArrayList<RfidSyncDataDO>();
            while (true) {
                RfidSyncDataDO rfidSyncDataDO = rfidSyncDataDOQueue.poll();
                if (rfidSyncDataDO != null) {
                    rfidSyncDataDOQueueArray.add(rfidSyncDataDO);
                } else {
                    //TODO 入库
                    if (rfidSyncDataDOQueueArray.size() > 0) {
                        exBaseStationDao.batchSaveRfidData(rfidSyncDataDOQueueArray);
                        exBaseStationDao.batchSaveRfidDataHistory(rfidSyncDataDOQueueArray);
                        log.info("{}  基站同步数据批量入库，队列数据已取完,当前数据长度size：{}", logSer, rfidSyncDataDOQueueArray.size());
                        //入库之后 清空
                        rfidSyncDataDOQueueArray.clear();
                    }
                    break;
                }

                if (rfidSyncDataDOQueueArray.size() >= 1000) {
                    //TODO 入库
                    exBaseStationDao.batchSaveRfidData(rfidSyncDataDOQueueArray);
                    exBaseStationDao.batchSaveRfidDataHistory(rfidSyncDataDOQueueArray);
                    log.info("{}  基站同步数据批量入库，标签数据长度大于1000先入库,当前数据长度size：{}", logSer, rfidSyncDataDOQueueArray.size());
                    //入库之后 清空
                    rfidSyncDataDOQueueArray.clear();
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //标签数据批量入库
        try {
            String testDeptIds = SystemUtil.getSystemParams().get(AnimalConstant.key_name_test_dept_ids).getParamValue();
            String autoEnterDataSwitch = SystemUtil.getSystemParams().get(AnimalConstant.key_name_auto_enter_data_switch).getParamValue();

            List<RfidLabelDO> rfidLabelDOQueueArray = new ArrayList<RfidLabelDO>();
            while (true) {
                RfidLabelDO rfidSyncDataDO = rfidLabelDOQueue.poll();
                if (rfidSyncDataDO != null) {
                    rfidLabelDOQueueArray.add(rfidSyncDataDO);
                } else {
                    //TODO 入库
                    if (rfidLabelDOQueueArray.size() > 0) {
                        batchSaveRfidData(rfidLabelDOQueueArray, AnimalConstant.use_status_yes, AnimalConstant.use_status_not, AnimalConstant.use_status_test, testDeptIds, autoEnterDataSwitch);
                        log.info("{}  标签数据批量入库，队列数据已取完,当前数据长度size：{}", logSer, rfidLabelDOQueueArray.size());
                        //入库之后 清空
                        rfidLabelDOQueueArray.clear();
                    }
                    break;
                }

                if (rfidLabelDOQueueArray.size() >= 1000) {
                    //TODO 入库
                    batchSaveRfidData(rfidLabelDOQueueArray, AnimalConstant.use_status_yes, AnimalConstant.use_status_not, AnimalConstant.use_status_test, testDeptIds, autoEnterDataSwitch);
                    log.info("{}  标签数据批量入库，标签数据长度大于1000先入库,当前数据长度size：{}", logSer, rfidLabelDOQueueArray.size());
                    //入库之后 清空
                    rfidLabelDOQueueArray.clear();
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void batchDeleteRfidDataHistory() {
        long logSer = System.currentTimeMillis();
        //删除N天前的历史数据  同步数据
        try {
            Integer day = Integer.valueOf(SystemUtil.getSystemParams().get(AnimalConstant.key_name_delete_n_day_rfid_data).getParamValue());
            Date date = UtilDate.getDateBefore(new Date(), day);
            int ret = exBaseStationDao.batchDeleteRfidDataHistory(date);
            log.info("{}  删除{}天前({})的数据，删除数据量{}", logSer, day, DateUtils.format(date, DateUtils.DATE_TIME_PATTERN), ret);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void batchRfidLabelData(long deptId) {
        exBaseStationDao.clearDeptLabel(deptId);
    }


    @Transactional
    public void batchSaveRfidData(List<RfidLabelDO> rfidLabelDOs,
                                  String useStatusYes,
                                  String useStatusNot,
                                  String useStatusTest,
                                  String testDeptIds,
                                  String autoEnterDataSwitch) {

        //01插入数据
        exBaseStationDao.batchInsertRfidLabel(rfidLabelDOs);

        if (AnimalConstant.open.equalsIgnoreCase(autoEnterDataSwitch)) {
            //02查询是否有新数据
            int newDataCount = exBaseStationDao.newRfidLabelDataCount();
            //03插入耳标录入表
            if (newDataCount > 0) {
                String batchNum = "L" + String.valueOf(System.currentTimeMillis());//批次号码
                //插入录入信息
                RfidLabelImportDO rfidLabelImportDO = new RfidLabelImportDO();
                rfidLabelImportDO.setImportBatchNum(batchNum);
                rfidLabelImportDO.setImportDatetime(new Date());
                rfidLabelImportDao.save(rfidLabelImportDO);
                exBaseStationDao.batchInsertLabelUseInfo(AnimalConstant.use_status_not, rfidLabelImportDO.getId());
            }
        }

        //04更新使用表
        exBaseStationDao.updateLabelUseStatus(AnimalConstant.use_status_yes, AnimalConstant.use_status_not, AnimalConstant.use_status_test, testDeptIds);
    }
}
